#include <iostream>
#include <string>
#include <fstream>
#include "cli/command_line.h"
#include "leveldb/db.h"
#include "lsm_tree/RecordVal.h"
#include "leveldb/options.h"
#include "config/conf.hpp"
#include "value_store/buffer.h"
#include <iostream>
#include <fstream>
#include <unistd.h>
#include "bootstrap/bootstrap.h"
#include <chrono>
#include <random>
#include <atomic>
#include <thread>
#include <iostream>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <chrono>
#include <fcntl.h>
#include <fstream>
#include <locale>
#include <codecvt>
#include <sys/mman.h>
#include <iostream>
#include <fstream>
#include <string_view>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <map>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <chrono>
#include "leveldb/status.h"
#include "leveldb/slice.h"

using namespace std;

void test1(){
    conf::Env ins = conf::Env::instance();
    ins.show_all_attrs();
    cout << " ---------------- " << endl;
    ins.set_section_attr("lsm", "db_engine", "rocksDB");
    ins.show_all_attrs();
    cout << " ---------------- " << endl;
    ins.set_section_attr("lsm", "name", "error!!");
    ins.show_all_attrs();
    cout << " ---------------- " << endl;
    cout << ins.get_section_attr("lll", "bbb") << endl;
    ins.show_all_attrs();
    conf::Section *s;
}


#define READ_SIZE 1024*1024


int testMmap(){
    int fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
        std::cerr << "Error opening file" << std::endl;
        return 1;
    }

    off_t fileSize = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);

    char *fileContents = static_cast<char *>(mmap(nullptr, READ_SIZE, PROT_READ, MAP_PRIVATE, fd, 0));
    if (fileContents == MAP_FAILED) {
        std::cerr << "Error mapping file to memory" << std::endl;
        close(fd);
        return 1;
    }
//    cout << fileContents << endl;
//    // 处理映射到内存的文件内容，可以直接通过指针访问
//    write(STDOUT_FILENO, fileContents, READ_SIZE);

    munmap(fileContents, fileSize);
    close(fd);

    return 0;
}



int mmapvswrite() {
    const char* filename_mmap = "example_mmap.txt";
    const char* filename_write = "example_write.txt";
    const size_t file_size =  10;  // 30MB

    // 使用 mmap 写入文件
    auto start_mmap = std::chrono::high_resolution_clock::now();

    int fd_mmap = open(filename_mmap, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    if (fd_mmap == -1) {
        perror("open (mmap)");
        return 1;
    }

    if (ftruncate(fd_mmap, file_size) == -1) {
        perror("ftruncate");
        close(fd_mmap);
        return 1;
    }

    char* file_data = (char*)mmap(NULL, file_size, PROT_WRITE, MAP_SHARED, fd_mmap, 0);
    if (file_data == MAP_FAILED) {
        perror("mmap");
        close(fd_mmap);
        return 1;
    }

    // 确保映射的内存被分配
    if (msync(file_data, file_size, MS_SYNC) == -1) {
        perror("msync");
    }

    memset(file_data, 'A', file_size);

    if (munmap(file_data, file_size) == -1) {
        perror("munmap");
    }

    close(fd_mmap);

    auto end_mmap = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double,std::milli> duration_mmap = end_mmap - start_mmap;

 /***************************************************************************************/

    // 使用 write 写入文件
    auto start_write = std::chrono::high_resolution_clock::now();

    int fd_write = open(filename_write, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    if (fd_write == -1) {
        perror("open (write)");
        return 1;
    }

    char* buffer = new char[file_size];
    memset(buffer, 'A', file_size);

    ssize_t bytes_written = write(fd_write, buffer, file_size);
    if (bytes_written == -1) {
        perror("write");
    }

    delete[] buffer;

    close(fd_write);

    auto end_write = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double,std::milli> duration_write = end_write - start_write;

    // 输出运行时间
    std::cout << "mmap duration: " << duration_mmap.count() << " milli seconds" << std::endl;
    std::cout << "write duration: " << duration_write.count() << " milli seconds" << std::endl;

    return 0;
}




void writeToDiskMMap(const std::map<std::string, std::string>& myMap, const char* filename, size_t size) {
    int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if (fd == -1) {
        perror("open (mmap)");
        return;
    }

    // 调整文件大小
    if (ftruncate(fd, size) == -1) {
        perror("ftruncate");
        close(fd);
        return;
    }

    // 使用 mmap 映射文件
    char* file_data = (char*)mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
    if (file_data == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return;
    }
    madvise(file_data, size, MADV_SEQUENTIAL);

//    // 确保映射的内存被分配
//    if (msync(file_data, serializedData.size(), MS_ASYNC) == -1) {
//        perror("msync");
//    }

    // 将数据写入映射的内存
    char* cur = file_data;
    for(auto& entry : myMap){
        auto key = entry.first;
        auto val = entry.second;
        memcpy(cur, key.c_str(), key.size());
        cur += key.size();
        memcpy(cur, val.c_str(), val.size());
        cur += val.size();
    }

//    std::string serializedData;
//    for (const auto& entry : myMap) {
//        serializedData += entry.first;
//        serializedData += entry.second;
//    }
//    auto dataLen = size;
//
//    memcpy(file_data, serializedData.c_str(), serializedData.size());


    // 解除映射
    if (munmap(file_data, size) == -1) {
        perror("munmap");
    }

    close(fd);
}

void writeToDiskWrite(const std::map<std::string, std::string>& myMap, const char* filename) {
    int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if (fd == -1) {
        perror("open (write)");
        return;
    }
    // 将 map 转换为一个连续的内存块
    std::string serializedData;
    for (const auto& entry : myMap) {
        serializedData += entry.first;
        serializedData += entry.second;
    }

    // 使用 write 写入文件
    ssize_t bytes_written = write(fd, serializedData.c_str(), serializedData.size());
    if (bytes_written == -1) {
        perror("write");
    }
    fsync(fd);
    close(fd);
}


int main2() {
    const char* filename_mmap = "map_data_mmap.txt";
    const char* filename_write = "map_data_write.txt";
    const char* filename_stream = "map_data_stream.txt";
    const size_t map_size = 2000000;  // 调整 map 的大小

    size_t size = 0;
    // 创建一个 std::map
    std::map<std::string, std::string> myMap;
    for (size_t i = 0; i < map_size; ++i) {
        string key = "key" + std::to_string(i);
        string val = "value" + std::to_string(i);
        size += (key.size() + val.size());
        myMap[key] = val;
    }

    // 使用 mmap 写入文件
    auto start_mmap = std::chrono::high_resolution_clock::now();
    writeToDiskMMap(myMap, filename_mmap, size);
    auto end_mmap = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double,std::milli> duration_mmap = end_mmap - start_mmap;


//    // 使用 stream 写入文件
//    auto start_stream = std::chrono::high_resolution_clock::now();
//    writeToDiskStream(myMap, filename_stream);
//    auto end_stream = std::chrono::high_resolution_clock::now();
//    std::chrono::duration<double,std::milli> duration_stream = end_stream - start_stream;
//
//    // 使用 write 写入文件
//    auto start_write = std::chrono::high_resolution_clock::now();
//    writeToDiskWrite(myMap, filename_write);
//    auto end_write = std::chrono::high_resolution_clock::now();
//    std::chrono::duration<double,std::milli> duration_write = end_write - start_write;


    // 输出运行时间
    std::cout << "mmap duration: " << duration_mmap.count() << " milli seconds" << std::endl;
//    std::cout << "write duration: " << duration_write.count() << " milli seconds" << std::endl;
//    std::cout << "stream duration: " << duration_stream.count() << " milli seconds" << std::endl;


    return 0;
}






/*******************************************/



std::string_view mmapSegment(const char* filename, int offset, int dataLen) {
    int fd = open(filename, O_RDONLY);
    if (fd == -1) {
        perror("Error opening file");
        return {};
    }

    char* data = (char*)mmap(nullptr, dataLen, PROT_READ, MAP_PRIVATE, fd, offset);
    madvise(data, dataLen, MADV_WILLNEED);
    close(fd);

    if (data == MAP_FAILED) {
        perror("Error mapping file");
        return {};
    }

    // Create a string_view referencing the specified segment
    std::string_view segment(data , dataLen);

    // Unmap the file
//    if (munmap(data, dataLen) == -1) {
//        perror("Error unmapping file");
//    }

    return segment;
}

int main3() {
    const char* filename = "map_data_mmap.txt";
    int pageSize = getpagesize(); //16kb
    off_t offset = 100*pageSize;  // Example offset
    size_t dataLen = pageSize*800;  // Example data length

    auto start_mmap = std::chrono::high_resolution_clock::now();
    std::string_view segment = mmapSegment(filename, offset, dataLen);
    auto end_mmap = std::chrono::high_resolution_clock::now();

    if (!segment.empty()) {
        // Use the segment (std::string_view) here
//        std::cout << "Segment data: " << segment << "\n";
    } else {
        std::cerr << "Failed to read segment\n";
    }
    std::chrono::duration<double,std::micro> duration_mmap = end_mmap - start_mmap;

    std::cout << "mmap duration: " << duration_mmap.count() << " micro seconds" << std::endl;

    return 0;
}

//读后写dhx，read+write vs mmap
int wrt(){
    vector<string> vec;
    for (int i = 0; i < 5000000; ++i) {
        vec.push_back(to_string(i)+'\n');
    }
    const char* filename = "dhx_example_from.txt";
    std::ofstream outFile(filename, std::ios::out);
    for(auto item : vec){
        outFile << item;
    }
    outFile.flush();
//    if (bytes_written == -1) {
//        perror("write");
//    }
    return 0;
}

int dhx1(){
    int ffrom = open("dhx_example_from.txt", O_RDONLY);
    if (ffrom == -1) {
        perror("Error opening fileA for reading");
        return 1;
    }

    off_t fileSize = lseek(ffrom, 0, SEEK_END);
    lseek(ffrom, 0, SEEK_SET);

    std::ofstream fto("dhx_example_to1.txt");

    char *buffer = new char[fileSize];
    read(ffrom, buffer, fileSize);

//    while (std::getline(inFile, line)) {
//        // 仅处理双数行
//        if (lineNumber % 2 == 0) {
//            outFile << line << std::endl;
//        }
//
//        lineNumber++;
//    }
    off_t i = 0;
    int curLineNum = 0;
    int len = 0;
    int fileBSize = 0;
    while (i < fileSize) {
        if (buffer[i] == '\n') {
            curLineNum++;
            // 判断是否是双数行
            if (curLineNum % 2 == 0) {
                // 写入双数行到文件B
                fto.write(buffer + i - len, len + 1);
                fileBSize += len+1;
            }
            // 移动到下一行
            len = 0;  // 重新从头开始检查新的行
        } else {
            ++len;
        }
        ++i;
    }

    fto.close();
    close(ffrom);

    return 0;
}

int dhx2(){
    // 打开文件A，获取文件大小
    int fdA = open("dhx_example_from.txt", O_RDONLY);
    if (fdA == -1) {
        perror("Error opening fileA for reading");
        return 1;
    }

    off_t fileSize = lseek(fdA, 0, SEEK_END);
    lseek(fdA, 0, SEEK_SET);

    // 映射文件A到内存
    char* data = (char*)mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fdA, 0);
    close(fdA);

    if (data == MAP_FAILED) {
        perror("Error mapping fileA to memory");
        return 1;
    }

    // 打开文件B，创建并打开
    int fdB = open("dhx_example_to2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (fdB == -1) {
        perror("Error opening fileB for writing");
        munmap(data, fileSize);
        cout << "unmap 1" << endl;
        return 1;
    }
    ftruncate(fdB, fileSize);

    // 仅写入data中的双数行到文件B
    off_t i = 0;
    int curLineNum = 0;
    int len = 0;
    int fileBSize = 0;
    while (i < fileSize) {
        if (data[i] == '\n') {
            curLineNum++;
            // 判断是否是双数行
            if (curLineNum % 2 == 0) {
                // 写入双数行到文件B
                if (write(fdB, data+i-len, len+1) == -1) {
                    perror("Error writing to fileB");
                    close(fdB);
                    munmap(data, fileSize);
                    cout << "unmap 2" << endl;
                    return 1;
                }
                fileBSize += len+1;
            }
            // 移动到下一行
            len = 0;  // 重新从头开始检查新的行
        } else {
            ++len;
        }
        ++i;
    }
    ftruncate(fdB, fileBSize);
    // 关闭文件B
    close(fdB);
    // 解除内存映射
    if (munmap(data, fileSize) == -1) {
        perror("Error unmapping memory");
        return 1;
    }

    return 0;
}



int read_leveldb(){
    leveldb::DB* db;
    leveldb::Options options;
    options.create_if_missing = false; // 如果数据库不存在，则不创建新的
    leveldb::Status status = leveldb::DB::Open(options, "/tmp/test_orderkv/lsm", &db);
    if (!status.ok()) {
        std::cerr << "Unable to open database: " << status.ToString() << std::endl;
        return 1;
    }

    // 创建一个迭代器
    leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());

    // 遍历所有键值对并输出
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        std::cout << "Key: " << it->key().ToString() << std::endl;
        auto lsmRecord = it->value().data();
        auto &recordVal = *reinterpret_cast<lsm::LsmRecordVal *>(const_cast<char *>(lsmRecord));
        cout << recordVal << endl;
    }
    if (!status.ok()) {
        std::cerr << "An error occurred while iterating: " << status.ToString() << std::endl;
    }
}

void read_vFile(const string& vFilePathStr){
    int fd = open(vFilePathStr.c_str(), O_RDONLY);
    if (fd == -1) {
        perror("Error opening vFile");
    }
    // Set the file offset
//    if (lseek(fd, startOffset, SEEK_SET) == -1) {
//        perror("Error setting file offset");
//        close(fd);
//    }
    auto scanLen = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);

    // Read data into buffer
    char buffer[scanLen];

    auto bytesRead = read(fd, buffer, scanLen);
    if (bytesRead == -1) {
        perror("Error reading file");
        close(fd);
    }

    auto fileSize  = scanLen;
    meta::f_off curOff = 0;
    while (curOff < fileSize) {
        meta::f_off recordLen;
        meta::f_off keyLen;
        std::memcpy(&recordLen, buffer + curOff, sizeof(meta::f_off));
        std::memcpy(&keyLen, buffer + curOff + sizeof(meta::f_off), sizeof(meta::f_off));
        string_view key = {buffer + curOff + 2 * sizeof(meta::f_off), keyLen};
        string_view val = {buffer + curOff + 2 * sizeof(meta::f_off) + keyLen,
                           recordLen - 2 * sizeof(meta::f_off) - keyLen};
        cout << key << "  " << val << endl;
        curOff += recordLen;
    }

    close(fd);
}

int main() {
    start();
//    read_leveldb();

//    read_vFile("/tmp/test_orderkv/vstore/vFile00000003.data");
//    cout << "-" << endl;
//    read_vFile("/tmp/test_orderkv/vstore/vFile00000004.data");
}